home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / INDENT3.ARJ / INDENT.C < prev    next >
C/C++ Source or Header  |  1992-08-04  |  15KB  |  509 lines

  1. /* Copyright (c) 1980 Regents of the University of California. All rights
  2.  * reserved.  The Berkeley software License Agreement specifies the terms and
  3.  * conditions for redistribution. */
  4.  
  5. #ifndef lint
  6. char copyright[] =
  7. "@(#) Copyright (c) 1980 Regents of the University of California.\n\
  8.  All rights reserved.\n";
  9. #endif not lint
  10.  
  11. #ifndef lint
  12. static char sccsid[] = "@(#)indent.c    5.4 (Berkeley) 9/10/85";
  13. #endif not lint
  14.  
  15. /*-
  16.   
  17.         Copyright (C) 1976
  18.                 by the
  19.         Board of Trustees
  20.                 of the
  21.         University of Illinois
  22.   
  23.         All rights reserved
  24.   
  25.   
  26. NAME:
  27. indent main program
  28.   
  29. FUNCTION:
  30. This is the main program of the indent program.  Indent will take a C
  31. program source and reformat it into a semi-reasonable form.
  32.   
  33. ALGORITHM:
  34. The routine lexi scans tokens and passes them back one at a time to the
  35. main routine.  The subroutine parse takes care of much of the work of
  36. figuring indentation level.  
  37.   
  38. 1) Call lexi
  39. 2) Enter a monster switch statement on the code returned by lexi.  If 
  40. the indentation level for the line yet to be printed should be 
  41. changed, set the variable ps.ind_level.  If the indentation level for
  42. the following line should be changed, set the variable ps.i_l_follow.
  43.   
  44. */
  45.  
  46. #include "indent_globs.h"
  47.  
  48. char *in_name = "<stdin>";    /* will always point to name of input file */
  49. char *out_name = "<stdout>";    /* will always point to name of output file */
  50. char bakfile[32] = "";
  51.  
  52. int dec_ind;            /* current indentation for declarations */
  53. int di_stack[STACKS];        /* a stack of structure indentation levels */
  54. int flushed_nl;            /* used when buffering up comments to
  55.                  * remember that a newline was passed over */
  56. int force_nl;            /* when true, code must be broken */
  57. int hd_type;            /* used to store type of stmt for if (...),
  58.                  * for (...), etc */
  59. int scase;            /* set to true when we see a case, so we will
  60.                  * know what to do with the following colon */
  61. int sp_sw;            /* when true, we are in the expressin of
  62.                  * if(...), while(...), etc. */
  63. int squest;            /* when this is positive, we have seen a ?
  64.                  * without the matching : in a <c>?<s>:<s>
  65.                  * construct */
  66. int type_code;            /* the type of token, returned by lexi */
  67.  
  68. int last_else = 0;        /* true iff last keyword was an else */
  69.  
  70. int is_procname;
  71.  
  72. #ifdef BUFFERING
  73. char *inbuf, *outbuf;        /* buffering buffers */
  74. #endif
  75.  
  76. void main(argc, argv)
  77.     int argc;
  78.     char **argv;
  79. {
  80.     register char *t_ptr;    /* used for copying tokens */
  81.     register int i;
  82.  
  83.     /*-----------------------------------------------*\
  84.      |               INITIALIZATION                  |
  85.     \*-----------------------------------------------*/
  86.  
  87.     sp_sw = force_nl = false;
  88.     dec_ind = 0;
  89.     squest = 0;
  90.     di_stack[ps.dec_nest = 0] = 0;
  91.     scase = ps.pcase = false;
  92.  
  93.     ps.p_stack[0] = stmt;    /* this is the parser's stack */
  94.     ps.last_nl = true;        /* this is true if the last thing scanned was
  95.                  * a newline */
  96.     ps.last_token = semicolon;
  97.     combuf[0] = codebuf[0] = labbuf[0] = ' ';    /* set up code, label, and
  98.                          * comment buffers */
  99.     combuf[1] = codebuf[1] = labbuf[1] = '\0';
  100.     s_lab = e_lab = labbuf + 1;
  101.     s_code = e_code = codebuf + 1;
  102.     s_com = e_com = combuf + 1;
  103.  
  104.     buf_ptr = buf_end = in_buffer;
  105.     line_no = 1;
  106.     had_eof = ps.in_decl = ps.decl_on_line = break_comma = false;
  107.     ps.in_or_st = false;
  108.     ps.bl_line = true;
  109.     ps.want_blank = ps.in_stmt = ps.ind_stmt = false;
  110.  
  111.     sc_end = 0;
  112.     bp_save = 0;
  113.     be_save = 0;
  114.  
  115.     output = NULL;
  116.  
  117.     /*--------------------------------------------------*\
  118.      |   COMMAND LINE SCAN
  119.     \*--------------------------------------------------*/
  120.  
  121.     set_defaults();
  122.  
  123.     /* Unfortunately, we must look for -npro here because the profiles are
  124.      * read before the command line arguments. */
  125.     for (i = 1; i < argc; ++i)
  126.     if (strcmp(argv[i], "-npro") == 0)
  127.         break;
  128.     if (i >= argc)
  129.     set_profile();
  130.  
  131.     input = NULL;        /* cancel -st if it was in the profiles, */
  132.     output = NULL;        /* as it doesn't make any sense there. */
  133.  
  134.     for (i = 1; i < argc; ++i) {
  135.  
  136.     /* look thru args (if any) for changes to defaults */
  137.  
  138.     if (argv[i][0] != '-') {/* no flag on parameter */
  139.         if (input == NULL) {/* we must have the input file */
  140.         in_name = argv[i];    /* remember name of input file */
  141.         input = fopen(in_name, "r");
  142.         if (input == NULL) {    /* check for open error */
  143.             fprintf(stderr, "indent: can't open %s\n", argv[i]);
  144.             exit(1);
  145.         }
  146.         continue;
  147.         } else if (output == NULL) {    /* we have the output file */
  148.         out_name = argv[i];    /* remember name of output file */
  149.         if (strcmp(in_name, out_name) == 0) {    /* attempt to overwrite
  150.                              * the file */
  151.             fprintf(stderr, "indent: input and output files must be different\n");
  152.             exit(1);
  153.         }
  154.         output = fopen(out_name, "w");
  155.         if (output == NULL) {    /* check for create error */
  156.             fprintf(stderr, "indent: can't create %s\n", argv[i]);
  157.             exit(1);
  158.         }
  159.         continue;
  160.         }
  161.         fprintf(stderr, "indent: unknown parameter: %s\n", argv[i]);
  162.         exit(1);
  163.     } else
  164.         set_option(argv[i]);
  165.  
  166.     }                /* end of for */
  167.     if (input == NULL) {
  168.     fprintf(stderr, "Usage: indent file [ outfile ] [ options ]\n");
  169.     exit(1);
  170.     }
  171.     if (output == NULL) {
  172.     if (troff)
  173.         output = stdout;
  174.     else {
  175.         out_name = in_name;
  176.         bakcopy();
  177.     }
  178.     }
  179. #ifdef BUFFERING
  180.     if ((inbuf = malloc(BUFSIZ)) == NULL || (outbuf = malloc(BUFSIZ)) == NULL) {
  181.     fprintf(stderr, "indent: out of memory!\n");
  182.     exit(1);
  183.     }
  184.     if (setvbuf(input, inbuf, _IOFBF, BUFSIZ) || setvbuf(output, outbuf, _IOFBF, BUFSIZ)) {
  185.     fprintf(stderr, "indent: bufferring error!\n");
  186.     exit(1);
  187.     }
  188. #endif
  189.  
  190.     /* Adjust parameters that are out of range, or set defaults if no values
  191.      * were specified. */
  192.     if (ps.com_ind <= 1)
  193.     ps.com_ind = 2;        /* dont put normal comments before column 2 */
  194.     if (block_comment_max_col <= 0)
  195.     block_comment_max_col = max_col;
  196.     if (ps.decl_com_ind <= 0)    /* if not specified by user, set this */
  197.     ps.decl_com_ind = ps.ljust_decl ? ps.com_ind - 8 : ps.com_ind;
  198.     if (ps.decl_com_ind <= 1)
  199.     ps.decl_com_ind = 2;
  200.     if (continuation_indent == 0)
  201.     continuation_indent = ps.ind_size;
  202.     fill_buffer();        /* get first batch of stuff into input buffer */
  203.  
  204.     parse(semicolon);
  205.  
  206.     dosomething();
  207.  
  208.     if (troff) {        /* this isn't going to work, but since there
  209.                  * isn't much call for troff on the PC, I
  210.                  * don't care. I'll leave it here though, for
  211.                  * your sake. */
  212.     register char *p = in_name, *beg = in_name;
  213.  
  214.     while (*p)
  215.         if (*p++ == '/')
  216.         beg = p;
  217.     fprintf(output, ".Fn \"%s\"\n", beg);
  218.     }
  219.     /*------------------------------*\
  220.      |     START OF MAIN LOOP       |
  221.     \*------------------------------*/
  222.     for (;;) {            /* this is the main loop.  it will go until
  223.                  * we reach eof */
  224.  
  225.     type_code = lexi();    /* lexi reads one token.  The actual
  226.                  * characters read are stored in "token".
  227.                  * lexi returns a code indicating the type of
  228.                  * token */
  229.     is_procname = ps.procname[0];
  230.  
  231.     /* The following code moves everything following an if (), while (),
  232.      * else, etc. up to the start of the following stmt to a buffer. This
  233.      * allows proper handling of both kinds of brace placement. */
  234.  
  235.     flushed_nl = false;
  236.     while (ps.search_brace) {    /* if we scanned an if(), while(),
  237.                      * etc., we might need to copy stuff
  238.                      * into a buffer we must loop,
  239.                      * copying stuff into save_com, until
  240.                      * we find the start of the stmt
  241.                      * which follows the if, or whatever */
  242.         switch (type_code) {
  243.         case newline:
  244.             ++line_no;
  245.             flushed_nl = true;
  246.         case form_feed:
  247.             break;    /* form feeds and newlines found here will be
  248.                  * ignored */
  249.  
  250.         case lbrace:    /* this is a brace that starts the compound
  251.                  * stmt */
  252.             if (sc_end == 0) {    /* ignore buffering if a comment
  253.                      * wasn't stored up */
  254.             ps.search_brace = false;
  255.             goto check_type;
  256.             }
  257.             if (btype_2) {
  258.             save_com[0] = '{';    /* we either want to put the
  259.                          * brace right after the if */
  260.             goto sw_buffer;        /* go to common code to get
  261.                          * out of this loop */
  262.             }
  263.         case comment:    /* we have a comment, so we must copy it into
  264.                  * the buffer */
  265.             if (!flushed_nl) {
  266.             if (sc_end == NULL) {    /* if this is the first
  267.                          * comment, we must set up
  268.                          * the buffer */
  269.                 save_com[0] = save_com[1] = ' ';
  270.                 sc_end = &(save_com[2]);
  271.             } else {
  272.                 *sc_end++ = '\n';    /* add newline between
  273.                          * comments */
  274.                 *sc_end++ = ' ';
  275.                 --line_no;
  276.             }
  277.             *sc_end++ = '/';    /* copy in start of comment */
  278.             *sc_end++ = '*';
  279.  
  280.             for (;;) {    /* loop until we get to the end of
  281.                      * the comment */
  282.                 *sc_end = *buf_ptr++;
  283.                 if (buf_ptr >= buf_end)
  284.                 fill_buffer();
  285.  
  286.                 if (*sc_end++ == '*' && *buf_ptr == '/')
  287.                 break;    /* we are at end of comment */
  288.  
  289.                 if (sc_end >= &(save_com[sc_size])) {    /* check for temp buffer
  290.                                      * overflow */
  291.                 diag(1, "Internal buff overflow - Move too large comment after if, while.");
  292.                 cleanup(1);
  293.                 }
  294.             }
  295.             *sc_end++ = '/';    /* add ending slash */
  296.             if (++buf_ptr >= buf_end)    /* get past / in buffer */
  297.                 fill_buffer();
  298.             break;
  299.             }
  300.         default:    /* it is the start of a normal statment */
  301.             if (flushed_nl)    /* if we flushed a newline, make sure
  302.                      * it is put back */
  303.             force_nl = true;
  304.             if (type_code == sp_paren && *token == 'i'
  305.             && last_else && ps.else_if
  306.             || type_code == sp_nparen && *token == 'e'
  307.             && e_code != s_code && e_code[-1] == '}')
  308.             force_nl = false;
  309.  
  310.             if (sc_end == NULL) {    /* ignore buffering if
  311.                          * comment wasnt saved up */
  312.             ps.search_brace = false;
  313.             goto check_type;
  314.             }
  315.             if (force_nl) {    /* if we should insert a nl here, put
  316.                      * it into the buffer */
  317.             force_nl = false;
  318.             --line_no;    /* this will be re-increased when the
  319.                      * nl is read from the buffer */
  320.             *sc_end++ = '\n';
  321.             *sc_end++ = ' ';
  322.             if (verbose && !flushed_nl)    /* print error msg if
  323.                              * the line was not
  324.                              * already broken */
  325.                 diag(0, "Line broken");
  326.             flushed_nl = false;
  327.             }
  328.             for (t_ptr = token; *t_ptr; ++t_ptr)
  329.             *sc_end++ = *t_ptr;    /* copy token into temp
  330.                          * buffer */
  331.  
  332.         sw_buffer:
  333.             ps.search_brace = false;    /* stop looking for start of
  334.                          * stmt */
  335.             bp_save = buf_ptr;    /* save current input buffer */
  336.             be_save = buf_end;
  337.             buf_ptr = save_com;        /* fix so that subsequent
  338.                          * calls to lexi will take
  339.                          * tokens out of save_com */
  340.             *sc_end++ = ' ';    /* add trailing blank, just in case */
  341.             buf_end = sc_end;
  342.             sc_end = 0;
  343.             break;
  344.         }            /* end of switch */
  345.         if (type_code != 0)    /* we must make this check, just in case
  346.                  * there was an unexpected EOF */
  347.         type_code = lexi();    /* read another token */
  348.         is_procname = ps.procname[0];
  349.     }            /* end of while (ps.search_brace) */
  350.     last_else = 0;
  351. check_type:
  352.     if (type_code == 0) {    /* we got eof */
  353.         if (s_lab != e_lab || s_code != e_code
  354.         || s_com != e_com)    /* must dump end of line */
  355.         dump_line();
  356.         if (ps.tos > 1)    /* check for balanced braces */
  357.         diag(1, "Stuff missing from end of file.");
  358.  
  359.         if (verbose) {
  360.         printf("There were %d output lines and %d comments\n",
  361.             ps.out_lines, ps.out_coms);
  362.         printf("(Lines with comments)/(Lines with code): %6.3f\n",
  363.             (1.0 * ps.com_lines) / code_lines);
  364.         }
  365.         cleanup(ps.tos <= 1);
  366.     }
  367.     if (
  368.         (type_code != comment) &&
  369.         (type_code != newline) &&
  370.         (type_code != preesc) &&
  371.         (type_code != form_feed)) {
  372.         if (force_nl && (type_code != semicolon) && (type_code != lbrace || !btype_2)) {    /* we should force a
  373.                                                  * broken line here */
  374.         if (verbose && !flushed_nl)
  375.             diag(0, "Line broken");
  376.         flushed_nl = false;
  377.         dump_line();
  378.         ps.want_blank = false;    /* dont insert blank at line start */
  379.         force_nl = false;
  380.         }
  381.         ps.in_stmt = true;    /* turn on flag which causes an extra level
  382.                  * of indentation. this is turned off by a ;
  383.                  * or '}' */
  384.         if (s_com != e_com) {    /* the turkey has embedded a comment
  385.                      * in a line. fix it */
  386.         *e_code++ = ' ';
  387.         for (t_ptr = s_com; *t_ptr; ++t_ptr)
  388.             *e_code++ = *t_ptr;
  389.         *e_code++ = ' ';
  390.         *e_code = '\0';    /* null terminate code sect */
  391.         ps.want_blank = false;
  392.         e_com = s_com;
  393.         }
  394.     } else if (type_code != comment)    /* preserve force_nl thru a
  395.                          * comment */
  396.         force_nl = false;
  397.  
  398.     /* cancel forced newline after newline, form feed, etc */
  399.  
  400.     switch_on(type_code);
  401.  
  402.     *e_code = '\0';        /* make sure code section is null terminated */
  403.     if (type_code != comment && type_code != newline && type_code != preesc)
  404.         ps.last_token = type_code;
  405.     }                /* end of main for(;;) loop */
  406. }
  407.  
  408. void dosomething()
  409. {
  410.     register char *p = buf_ptr;
  411.     register col = 1;
  412.  
  413.     for (;;) {
  414.     if (*p == ' ')
  415.         col++;
  416.     else if (*p == '\t')
  417. #if 0
  418.         col = ((col - 1) & tabmask) + 9;
  419. #else
  420.         col += tabsize - (col % tabsize) + 1;
  421. #endif
  422.     else
  423.         break;
  424.     p++;
  425.     }
  426.     if (col > ps.ind_size)
  427.     ps.ind_level = ps.i_l_follow = col / ps.ind_size;
  428. }
  429. /* clean up procedure */
  430. void cleanup(ret)
  431.     int ret;
  432. {
  433.     if (output != NULL) {
  434.     fflush(output);
  435.     fclose(output);
  436.     }
  437.     if (input != NULL) {
  438.     fclose(input);
  439.     }
  440. #ifdef BUFFERING
  441.     if (inbuf != NULL) {
  442.     free(inbuf);
  443.     }
  444.     if (outbuf != NULL) {
  445.     free(outbuf);
  446.     }
  447. #endif
  448.     exit(ret);
  449. }
  450.  
  451. /* copy input file to backup file.  If in_name is /blah/blah/blah/file.foo,
  452.  * then backup file will be "file.BAK".  Then make the backup file the input
  453.  * and original input file the output. */
  454. void bakcopy()
  455. {
  456.     int n;
  457.     FILE *bakchn;
  458.     char extsave[16];        /* MS DOS extension */
  459.     register char *p;
  460.     char *r;
  461.  
  462.     while ((p = strchr(in_name, '\\')) != NULL) {
  463.     /* copy from `\' to end */
  464.     p++;
  465.     in_name = p;
  466.     }
  467.     p = in_name;
  468.  
  469.     /* wack off stuff after `.' */
  470.     if ((r = strchr(p, '.')) != NULL) {
  471.     strcpy(extsave, (r + 1));
  472.     *r = NIL;        /* terminate string there */
  473.     }
  474.     sprintf(bakfile, "%s.BAK", p);
  475.  
  476.     /* restore original in_name */
  477.     sprintf(in_name, "%s.%s", in_name, extsave);
  478.  
  479.     /* copy in_name to backup file */
  480.     if ((bakchn = fopen(bakfile, "w")) == NULL) {
  481.     fprintf(stderr, "indent: can't create backup file \"%s\"\n", bakfile);
  482.     exit(1);
  483.     }
  484.     /* copy input file to backup file */
  485.     while ((n = getc(input)) != EOF)
  486.     putc(n, bakchn);
  487.  
  488.     if ((n = fclose(bakchn)) == EOF) {
  489.     fprintf(stderr, "indent: error closeing backup file\n");
  490.     exit(1);
  491.     }
  492.     if ((n = fclose(input)) == EOF) {
  493.     fprintf(stderr, "indent: error closeing input file\n");
  494.     exit(1);
  495.     }
  496.     /* re-open backup file as the input file */
  497.     if ((input = fopen(bakfile, "r")) == NULL) {
  498.     fprintf(stderr, "indent: can't re-open backup file\n");
  499.     exit(1);
  500.     }
  501.     /* now the original input file will be the output */
  502.     output = fopen(in_name, "w");
  503.     if (output == NULL) {
  504.     fprintf(stderr, "indent: can't create %s\n", in_name);
  505.     unlink(bakfile);
  506.     exit(1);
  507.     }
  508. }
  509.